#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cJSON.h"

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include "iconv.h"

#include "libxml/parser.h"
#include "libxml/xmlmemory.h"


#define LEN 1024*1024
int json2xml_exec(char *json_str,char *xml_data,int xml_len,int flag);


char *json2xml(char *json_str)
{
	char *xml_data = (char *)malloc(sizeof(char) * LEN );	
	memset(xml_data,0x00,LEN);
	snprintf(xml_data,LEN,"%s","<?xml version=\"1.0\" encoding=\"UTF-8\"?><json2xml>");
	json2xml_exec(json_str,xml_data,LEN,0);
	snprintf(xml_data+strlen(xml_data),LEN-strlen(xml_data),"%s","</json2xml>");
	printf("%s\n",xml_data);
	return xml_data;
}

int json2xml_exec(char *json_str,char *xml_data,int xml_len,int flag)
{
	cJSON *pRoot = cJSON_Parse(json_str);
	if(pRoot == NULL)
	{
		printf("josn string format error\n");
		return -1;
	}	
	if(flag)
	{
		cJSON_free(json_str);
	}
	cJSON_free(json_str);
	cJSON *pChild = pRoot -> child;
	while(pChild != NULL)
	{
		if(pChild -> child != NULL)
		{
			char *strSubKey = pChild -> string;
			snprintf(xml_data+strlen(xml_data),xml_len-strlen(xml_data),"<%s>",strSubKey);
			json2xml_exec(cJSON_Print(pChild),xml_data,xml_len,1);
			snprintf(xml_data+strlen(xml_data),xml_len-strlen(xml_data),"</%s>",strSubKey);
			
		}	
		else
		{
			char *strKey = pChild->string;
			snprintf(xml_data+strlen(xml_data),xml_len-strlen(xml_data),"<%s>",strKey);
			if(pChild->valuestring != NULL)
			{
				char *strv = pChild->valuestring;
				snprintf(xml_data+strlen(xml_data),xml_len-strlen(xml_data),"%s",strv);
			}
			else
			{
				char *douv = cJSON_Print(pChild);
				snprintf(xml_data+strlen(xml_data),xml_len-strlen(xml_data),"%s",douv);
				cJSON_free(douv);
			}
			snprintf(xml_data+strlen(xml_data),xml_len-strlen(xml_data),"</%s>",strKey);
		}
		pChild = pChild->next;
	}	
	if(pRoot != NULL)
	{
		cJSON_Delete(pRoot);
	}
	return 0;

}

int get_json_param_value(char *json_str,int *json_len,char *key_val,char *value_val,int *value_len)
{
	if(*json_len > LEN)
	{
		printf("dest_len[%d] is too big for MAX_LEN[%d]",*json_len,LEN);
	}	
	cJSON *pRoot = cJSON_Parse(json_str);
	if(pRoot == NULL)
	{
		printf("josn string format error\n");
		return -1;
	}	

	cJSON *pChild = pRoot -> child;
	while(pChild != NULL)
	{
		char *strKey = pChild->string;
		if(!strcmp(strKey,key_val))
		{
			memset(value_val,0x00,*value_len);
			char *strv;
			if(pChild->valuestring != NULL)
			{
				strv = pChild->valuestring;
			}
			else
			{
				strv = cJSON_Print(pChild);
			}
			if(strlen(strv) > *value_len)
			{
				printf("strv is too long\n");
				break;
			}
			snprintf(value_val,*value_len,"%s",strv);	
			break;
		}
		else
		{
			pChild = pChild->next;
		}
	}	
	if(pRoot != NULL)
	{
		cJSON_Delete(pRoot);
	}
	return 0;
}


static int string_conv(const char *from_charset,const char *to_charset,char *inbuf,size_t inlen,char *outbuf,size_t *outlen)
{
	iconv_t cd;
	size_t iResult;
	char **pin = &inbuf;
	char **pout = &outbuf;
	cd = iconv_open(to_charset,from_charset);	
	if(cd < 0)
	{
		fprintf(stderr,"conv code error:%s[%d]\n",strerror(errno),errno);
		return -1;
	}
	memset(outbuf,0x00,*outlen);
	iResult = iconv(cd,pin,&inlen,pout,outlen);
	iconv_close(cd);
	return iResult;
}


void xml_json(xmlNodePtr xml_node,cJSON **json_node,char *root_name)
{
	xmlNodePtr xml_cur = NULL,xml_loop = NULL,xml_tmp = NULL;
	xmlAttrPtr xml_attr = NULL;
	cJSON *json_cur = NULL,*json_array = NULL;
	char szName[1025],szValue[1024];
	xmlChar *pszContent = NULL;
	size_t len = 0;

	if(root_name != NULL && !strcmp((char *)xml_node->name,root_name))
	{
		xml_node = xml_node->children;
	}
	
	for(xml_cur = xml_node;xml_cur;xml_cur = xml_cur->next)
	{
		if(xml_cur->type == XML_ELEMENT_NODE)
		{
			if(xml_cur->children->type == XML_TEXT_NODE)
			{
				xml_loop = xml_cur->next;
				while(xml_loop)
				{
					xml_tmp = xml_loop->next;
					if(xmlStrcmp(xml_loop->name,xml_cur->name) == 0)	
					{
						if(json_array == NULL)
							json_array = cJSON_CreateArray();
						xml_attr = xml_loop->properties;
						if(xml_attr == NULL)
						{
							memset(szValue,0x00,sizeof(szValue));
							pszContent = xmlNodeGetContent(xml_loop);
							//len = strlen((char *)pszContent);
							//string_conv("UTF-8","GBK",(char *)pszContent,strlen((char *)pszContent),szValue,&len);
							snprintf(szValue,sizeof(szValue),"%s",pszContent);
							xmlFree(pszContent);
							json_cur = cJSON_CreateString(szValue);	
						}
						else
						{
							memset(szName,0x00,sizeof(szName));
							snprintf(szName,sizeof(szName),"%s","#text");
							json_cur = cJSON_CreateObject();
							memset(szValue,0x00,sizeof(szValue));
							pszContent = xmlNodeGetContent(xml_loop);
							//len = strlen((char *)pszContent);
							//string_conv("UTF-8","GBK",(char *)pszContent,strlen((char *)pszContent),szValue,&len);
							snprintf(szValue,sizeof(szValue),"%s",pszContent);
							xmlFree(pszContent);
							cJSON_AddStringToObject(json_cur,szName,szValue);
							while(xml_attr)
							{
								memset(szName,0x00,sizeof(szName));
								snprintf(szName,sizeof(szName),"@%s",xml_attr->name);
								memset(szValue,0x00,sizeof(szValue));
								//string_conv("UTF-8","GBK",(char *)xml_attr->children->content,strlen((char *)xml_attr->children->content),szValue,&len);
								snprintf(szValue,sizeof(szValue),"%s",xml_attr->children->content);
								cJSON_AddStringToObject(json_cur,szName,szValue);
								xml_attr = xml_attr->next;
								
							}
						}
						cJSON_AddItemToArray(json_array,json_cur);	
						if(json_array != NULL)
						{
							cJSON_Delete(json_array);
							json_array = NULL;
						}	
						xmlUnlinkNode(xml_loop);
						xmlFreeNode(xml_loop);
					}
					xml_loop = xml_tmp;
				}
				xml_attr = xml_cur->properties;
				if(xml_attr == NULL)
				{
					memset(szValue,0x00,sizeof(szValue));
					pszContent = xmlNodeGetContent(xml_cur);
					len = strlen((char *)pszContent);
					//string_conv("UTF-8","GBK",(char *)pszContent,strlen((char *)pszContent),szValue,&len);
					snprintf(szValue,sizeof(szValue),"%s",pszContent);
					xmlFree(pszContent);
					json_cur = cJSON_CreateString(szValue);
				}
				else
				{
					json_cur = cJSON_CreateObject();
					memset(szName,0x00,sizeof(szName));	
					snprintf(szName,sizeof(szName),"%s","#text");
					memset(szValue,0x00,sizeof(szValue));
					pszContent = xmlNodeGetContent(xml_cur);
					len = strlen((char *)pszContent);
					//string_conv("UTF-8","GBK",(char *)pszContent,strlen((char *)pszContent),szValue,&len);
					snprintf(szValue,sizeof(szValue),"%s",pszContent);
					xmlFree(pszContent);
					cJSON_AddStringToObject(json_cur,szName,szValue);
					while(xml_attr)
					{
						memset(szName,0x00,sizeof(szName));	
						snprintf(szName,sizeof(szName),"@%s",xml_attr->name);
						memset(szValue,0x00,sizeof(szValue));
						len = strlen((char *)xml_attr->children->content); 
						//string_conv("UTF-8","GBK",(char *)xml_attr->children->content,strlen((char *)xml_attr->children->content),szValue,&len);
						snprintf(szValue,sizeof(szValue),"%s",xml_attr->children->content);
						cJSON_AddStringToObject(json_cur,szName,szValue);
						xml_attr = xml_attr->next;
					}
				}
				if(json_array != NULL)
				{
					cJSON_AddItemToArray(json_array,json_cur);
					cJSON_AddItemToObject(*json_node,(char *)xml_cur->name,json_array);
					json_array = NULL;
				}
				else
				{
					cJSON_AddItemToObject(*json_node,(char *)xml_cur->name,json_cur);
				}
			}
			else if(xml_cur->children->type == XML_ELEMENT_NODE)
			{
				xml_loop = xml_cur->next;
				while(xml_loop)
				{
					xml_tmp = xml_loop->next;
					printf("line 277 = [%s]\n","1111111111111111111111");
					if(xmlStrcmp(xml_loop->name,xml_cur->name) == 0)
					{
						fprintf(stdout,"--loop[%s]\n",xml_loop->name);
						if(json_array == NULL)
							json_array = cJSON_CreateArray();
						json_cur = cJSON_CreateObject();
						xml_attr = xml_loop->properties;	
						while(xml_attr)
						{
							memset(szName,0x00,sizeof(szName));
							snprintf(szName,sizeof(szName)-1,"@%s",xml_attr->name);
							memset(szValue,0x00,sizeof(szValue));
							len = strlen((char *)xml_attr->children->content);
							//string_conv("UTF-8","GBK",(char *)xml_attr->children->content,strlen((char *)xml_attr->children->content),szValue,&len);
							snprintf(szValue,sizeof(szValue),"%s",xml_attr->children->content);
							cJSON_AddStringToObject(json_cur,szName,szValue);
							xml_attr = xml_attr->next;
						}
						xml_json(xml_loop->children,&json_cur,NULL);
						cJSON_AddItemToArray(json_array,json_cur);
						xmlUnlinkNode(xml_loop);
						xmlFreeNode(xml_loop);
					}
					xml_loop = xml_tmp;
				}
				json_cur = cJSON_CreateObject();
				xml_attr = xml_cur->properties;
				while(xml_attr)
				{
					memset(szName,0x00,sizeof(szName));
					snprintf(szName,sizeof(szName)-1,"@%s",xml_attr->name);
					memset(szValue,0x00,sizeof(szValue));
					len = strlen((char *)xml_attr->children->content);
					//string_conv("UTF-8","GBK",(char *)xml_attr->children->content,strlen((char *)xml_attr->children->content),szValue,&len);
					snprintf(szValue,sizeof(szValue),"%s",xml_attr->children->content);
					cJSON_AddStringToObject(json_cur,szName,szValue);
					xml_attr = xml_attr->next;
				}
				xml_json(xml_cur->children,&json_cur,NULL);
				if(json_array != NULL)
				{
					cJSON_AddItemToArray(json_array,json_cur);
					cJSON_AddItemToObject(*json_node,(char *)xml_cur->name,json_array);
					json_array = NULL;
				}
				else
				{
					cJSON_AddItemToObject(*json_node,(char *)xml_cur->name,json_cur);
				}
			}	
		}
	}
	return ;
}

int xml2json(const char *xml,const int xml_len,char *json,int json_len)
{
	xmlBufferPtr buff;
	xmlDocPtr xml_doc;
	xmlNodePtr xml_root;
	cJSON *json_root;
	xmlKeepBlanksDefault(0);
	buff = xmlBufferCreate();
	//xml_doc = xmlReadMemory(xml,xml_len,"","GBK",0);	
	xml_doc = xmlReadMemory(xml,xml_len,"","",0);	
	if(xml_doc == NULL)
	{
		fprintf(stderr,"read xml error\n");
		return -1;
	}
	xml_root = xmlDocGetRootElement(xml_doc);
	if(xml_root == NULL)
	{
		fprintf(stderr,"get xml root node error\n");
		xmlFree(xml_doc);
		return -1;
	}
	json_root = cJSON_CreateObject();
	xml_json(xml_root,&json_root,(char *)xml_root->name);
	int len = snprintf(json,json_len,"%s",cJSON_Print(json_root));
	cJSON_Delete(json_root);
	xmlFreeDoc(xml_doc);
	xmlBufferFree(buff);
	xmlCleanupParser();
	return len;
}
